﻿using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;
using ZL_Framework;

public class BuildAssetBundlesTool
{
    [MenuItem("AssetBundle/生成配置")]
    public static void CreateConfig()
    {
        DirectoryInfo dirInfo = new DirectoryInfo("Assets/ExcelConfig");
        FileSystemInfo[] fsinfos = dirInfo.GetFileSystemInfos();
        for (int j = 0; j < fsinfos.Length; j++)
        {
            if (fsinfos[j].Name.EndsWith(".xlsx"))
            {
                string filePath = fsinfos[j].FullName.Replace('\\', '/');

                ExcelUtility excel = new ExcelUtility(filePath);

                string output = Application.dataPath + "/AssetBundles/Config/" + fsinfos[j].Name;
                output = output.Replace(".xlsx", ".json");
                excel.ConvertToJson(output, Encoding.GetEncoding("utf-8"));
                UpdateProgress(0, 1, "正在导入游戏配置");
            }
        }
        AssetDatabase.Refresh();
        UnityEngine.Debug.Log("******游戏配置导入成功******");
        EditorUtility.ClearProgressBar();
    }

    [MenuItem("AssetBundle/设置AB名称/单个或多个资源")]
    public static void SetSelectFolderFileBundleName()
    {
        EditorUtility.ClearProgressBar();
        UnityEngine.Object[] selObj = Selection.GetFiltered(typeof(Object), SelectionMode.Unfiltered);
        int curr = 0;
        int total = selObj.Length;
        foreach (Object item in selObj)
        {
            string objPath = AssetDatabase.GetAssetPath(item);
            UnityEngine.Debug.Log(objPath);
            FileInfo fileInfo = new FileInfo(objPath);
            if (fileInfo.Attributes == FileAttributes.Directory)
            {
                AssetDatabase.Refresh();
                UnityEngine.Debug.LogError("******选中了文件夹对象！******");
                EditorUtility.ClearProgressBar();
                return;
            }
            string filePath = fileInfo.FullName.Replace('\\', '/');
            filePath = filePath.Replace(Application.dataPath, "Assets");
            AssetImporter ai = AssetImporter.GetAtPath(filePath);
            curr++;
            UpdateProgress(curr, total, "正在设置AssetBundle包名 " + filePath);
            string bundle_name;
            bundle_name = filePath.Replace('/', '-');
            bundle_name = bundle_name.Replace(" ", "(_)");
            ai.assetBundleName = bundle_name.Split('.')[0] + ".assetbundle";
        }
        AssetDatabase.Refresh();
        UnityEngine.Debug.Log("******设置AssetBundle名称成功******");
        EditorUtility.ClearProgressBar();
    }

    [MenuItem("AssetBundle/设置AB名称/整个文件夹下所有文件")]
    public static void SetSelectFolderFileSameBundleName()
    {
        SetDirFileABName(false);
    }

    [MenuItem("AssetBundle/设置AB名称/AssetBundles路径下所有资源")]
    public static void SetBundleNameWithDirectory()
    {
        string path = Path.Combine(Application.dataPath, "AssetBundles/");
        SetAssetbundleName(path, false);
        AssetDatabase.Refresh();
        UnityEngine.Debug.Log("******批量设置AssetBundle名称成功******");
    }

    [MenuItem("AssetBundle/清理AB名称/AssetBundles路径下所有资源")]
    public static void ResetBundleName()
    {
        string path = Path.Combine(Application.dataPath, "AssetBundles/");
        SetAssetbundleName(path, true);
        AssetDatabase.Refresh();
        UnityEngine.Debug.Log("******批量清理AssetBundle名称成功******");
    }

    public static void SetAssetbundleName(string path, bool isClear)
    {
        EditorUtility.ClearProgressBar();
        DirectoryInfo d = new DirectoryInfo(path);
        FileSystemInfo[] fsinfos = d.GetFileSystemInfos();
        int curr = 0;
        int total = fsinfos.Length / 2;
        foreach (FileSystemInfo fsinfo in fsinfos)
        {
            if (fsinfo.Attributes == FileAttributes.Directory)     //判断是否为文件夹
            {
                SetAssetbundleName(fsinfo.FullName, isClear);//递归调用
            }
            else
            {
                if (fsinfo.Extension == ".meta")
                    continue;
                FileInfo fileInfo = new FileInfo(fsinfo.FullName);
                string filePath = fileInfo.FullName.Replace('\\', '/');
                string dirPath = Path.GetDirectoryName(fileInfo.FullName);
                dirPath = dirPath.Replace('\\', '/');
                dirPath = dirPath.Replace(Application.dataPath, "Assets");
                curr++;
                UpdateProgress(curr, total, "正在设置AssetBundle包名 " + dirPath);
                filePath = filePath.Replace(Application.dataPath, "Assets");
                AssetImporter ai = AssetImporter.GetAtPath(filePath);
                UnityEngine.Debug.Log(dirPath);
                string bundle_name;
                if (isClear)
                {
                    bundle_name = null;
                }
                else
                {
                    bundle_name = dirPath.Replace('/', '-');
                    bundle_name = bundle_name.Replace(" ", "(_)");
                    bundle_name = bundle_name + ".assetbundle";
                }
                ai.assetBundleName = bundle_name;
            }
        }
        EditorUtility.ClearProgressBar();
    }

    /// <summary>  
    /// 批量清空所选文件夹下资源的AssetBundleName.  
    /// </summary>  
    [MenuItem("AssetBundle/清理AB名称/所选文件夹下资源")]
    public static void ResetSelectFolderFileBundleName()
    {
        SetDirFileABName(true);
    }

    private static void SetDirFileABName(bool isClear)
    {
        EditorUtility.ClearProgressBar();
        UnityEngine.Object[] selObj = Selection.GetFiltered(typeof(Object), SelectionMode.Unfiltered);
        int curr = 0;
        int total = selObj.Length;
        foreach (Object item in selObj)
        {
            string selectFilePath = AssetDatabase.GetAssetPath(item);
            UnityEngine.Debug.Log(selectFilePath);
            DirectoryInfo dirInfo = new DirectoryInfo(selectFilePath);
            if (dirInfo.Attributes != FileAttributes.Directory)
            {
                AssetDatabase.Refresh();
                EditorUtility.ClearProgressBar();
                UnityEngine.Debug.LogError("******选中了非文件夹对象!******");
                return;
            }
            string bundle_name;
            if (isClear)
            {
                bundle_name = null;
            }
            else
            {
                bundle_name = selectFilePath.Replace('/', '-');
                bundle_name = bundle_name.Replace(" ", "(_)");
                bundle_name = bundle_name.Split('.')[0] + ".assetbundle";
            }

            FileSystemInfo[] fsinfos = dirInfo.GetFileSystemInfos();
            for (int j = 0; j < fsinfos.Length; j++)
            {
                DirectoryInfo temp = new DirectoryInfo(fsinfos[j].FullName);
                if (fsinfos[j].Attributes == FileAttributes.Directory)
                {
                    UnityEngine.Debug.LogError("******文件夹不处理******");
                    continue;
                }
                if (fsinfos[j].Extension == ".meta")
                    continue;
                string filePath = fsinfos[j].FullName.Replace('\\', '/');
                filePath = filePath.Replace(Application.dataPath, "Assets");
                UpdateProgress(curr, total, "正在设置AssetBundle包名 " + filePath);
                AssetImporter ai = AssetImporter.GetAtPath(filePath);
                ai.assetBundleName = bundle_name;
            }
            curr++;
        }
        AssetDatabase.Refresh();
        if (isClear)
            UnityEngine.Debug.Log("******批量清理AssetBundle名称成功******");
        else
            UnityEngine.Debug.Log("******批量设置AssetBundle同一个名称成功******");
        EditorUtility.ClearProgressBar();
    }

    static string bundlePath = Application.streamingAssetsPath + "/serverassets/assetbundle/";
    /// <summary>
    /// 自动打包资源（设置了Assetbundle Name的资源）
    /// </summary>
    [MenuItem("AssetBundle/打包/打包资源")]
    public static void BuildAllAssetBundles()
    {
        if (!Directory.Exists(bundlePath))
        {
            Directory.CreateDirectory(bundlePath);
        }
        else
        {
            DeleteFile(bundlePath);
            Directory.CreateDirectory(bundlePath);
        }
        Caching.ClearCache();
        //打包资源
#if UNITY_ANDROID
        BuildPipeline.BuildAssetBundles(bundlePath, BuildAssetBundleOptions.ChunkBasedCompression | BuildAssetBundleOptions.DeterministicAssetBundle, BuildTarget.Android);
#elif UNITY_IOS || UNITY_IPHONE
        BuildPipeline.BuildAssetBundles(bundlePath, BuildAssetBundleOptions.ChunkBasedCompression | BuildAssetBundleOptions.DeterministicAssetBundle, BuildTarget.iOS);
#endif
        //刷新编辑器
        AssetDatabase.Refresh();

    }

    [MenuItem("AssetBundle/打包/打包Lua脚本")]
    public static void BuildLuaScripts()
    {
        string resPath = Path.Combine(Application.streamingAssetsPath, "serverassets");

        string luaPath = Path.Combine(resPath, "luascripts");

        if (!Directory.Exists(luaPath))
        {
            Directory.CreateDirectory(luaPath);
        }
        else
        {
            DeleteFile(luaPath);
            Directory.CreateDirectory(luaPath);
        }

        int cur = 0;
        int total = 0;

        string luaPaths = Application.dataPath + "/Scripts/LuaScripts/";
        LuaSerializeFile luaFile = ScriptableObject.CreateInstance<LuaSerializeFile>();

        EditorUtility.ClearProgressBar();

        files.Clear();
        Recursive(luaPaths);

        total = files.Count;
        foreach (string f in files)
        {
            cur++;
            UpdateProgress(cur, total, "正在打包Lua脚本 " + f);
            Debug.Log("files=" + f);
            if (f.EndsWith(".meta"))
                continue;
            if (f.Contains(".idea"))
                continue;
            string newfile = f.Replace(luaPaths, "");
            string newpath = Path.Combine(luaPath, newfile);

            if (File.Exists(newpath))
            {
                File.Delete(newpath);
            }
            if (f.Contains(".lua"))
            {
                string fileName = Path.GetFileNameWithoutExtension(f);
                luaFile.AddLuaFile(fileName, Encoding.UTF8.GetBytes(File.ReadAllText(f, Encoding.UTF8)));
            }
            else
            {
                string path = Path.GetDirectoryName(newpath);
                if (!Directory.Exists(path))
                    Directory.CreateDirectory(path);

                File.Copy(f, newpath, true);
            }

        }

        string luaFilePath = Path.Combine("Assets", "lua.asset");
        string luaAssetPath = luaFilePath.Replace('\\', '/');
        luaAssetPath = luaAssetPath.Replace(Application.dataPath, "Assets");

        UnityEngine.Debug.Log("luaFile=" + luaFile.files.Count);
        UnityEngine.Debug.Log("luaAssetPath=" + luaAssetPath);
        AssetDatabase.CreateAsset(luaFile, luaAssetPath);
        AssetDatabase.Refresh();

        AssetBundleBuild build = new AssetBundleBuild();
        build.assetNames = new string[] { luaAssetPath };
        build.assetBundleName = "lua.assetbundle";

        Debug.Log("luaPath=" + luaPath);
        BuildPipeline.BuildAssetBundles(luaPath + "/", new[] { build }, BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.Android);
        File.Delete(luaFilePath);

        AssetDatabase.Refresh();
        EditorUtility.ClearProgressBar();
    }

    static List<string> paths = new List<string>();
    static List<string> files = new List<string>();

    /// <summary>
    /// 遍历目录及其子目录
    /// </summary>
    static void Recursive(string path)
    {
        string[] names = Directory.GetFiles(path);
        string[] dirs = Directory.GetDirectories(path);
        foreach (string filename in names)
        {
            string ext = Path.GetExtension(filename);
            if (ext.Equals(".meta")) continue;
            files.Add(filename);
        }
        foreach (string dir in dirs)
        {
            paths.Add(dir);
            Recursive(dir);
        }
    }

    [MenuItem("AssetBundle/打包/生成资源文件列表")]
    public static void CreateFileList()
    {
        string resPath = Path.Combine(Application.streamingAssetsPath, "serverassets");
        string newFilePath = Path.Combine(resPath, "files.txt");
        if (File.Exists(newFilePath))
            File.Delete(newFilePath);

        EditorUtility.ClearProgressBar();

        paths.Clear(); files.Clear();
        Recursive(resPath);

        int cur = 0;
        int total = files.Count;

        FileStream fs = new FileStream(newFilePath, FileMode.CreateNew);
        StreamWriter sw = new StreamWriter(fs);
        for (int i = 0; i < files.Count; i++)
        {
            string file = files[i];
            string ext = Path.GetExtension(file);
            if (file.EndsWith(".meta") || file.EndsWith(".manifest") || file.Contains(".DS_Store")) continue;

            string md5 = Extensions.GetFileMD5(file);
            string value = file.Replace(resPath, string.Empty).Replace("\\", "/").TrimStart('/');

            long length = Extensions.GetFileLength(file);

            sw.WriteLine(value + "|" + md5 + "|" + length);

            cur++;
            UpdateProgress(cur, total, "正在生成资源文件列表 " + file);
        }
        sw.Close(); fs.Close();

        AssetDatabase.Refresh();
        EditorUtility.ClearProgressBar();
    }

    [MenuItem("AssetBundle/一键全自动打包（资源，Lua脚本）")]
    public static void AllBuild()
    {
        //CreateConfig();
        SetBundleNameWithDirectory();
        BuildAllAssetBundles();
        BuildLuaScripts();
        CreateFileList();

        EditorUtility.DisplayDialog("资源打包完成", "资源打包完成", "确定");
    }

    [MenuItem("AssetBundle/删除全部资源包（资源，Lua脚本）")]
    public static void DeleteAllRes()
    {
        string resPath = Path.Combine(Application.streamingAssetsPath, "serverassets");
        DeleteFile(resPath);
        AssetDatabase.Refresh();
    }

    public static void DeleteFile(string path)
    {
        FileAttributes attr = File.GetAttributes(path);
        if (attr == FileAttributes.Directory)
        {
            Directory.Delete(path, true);
        }
        else
        {
            File.Delete(path);
        }
    }

    static void UpdateProgress(int progress, int progressMax, string desc)
    {
        string title = "Processing...[" + progress + " - " + progressMax + "]";
        float value = (float)progress / (float)progressMax;
        EditorUtility.DisplayProgressBar(title, desc, value);
    }
}